// Contient toutes les spécifications de classes nécessaires pour représenter l'arbre abstrait

#ifndef ARBRE_H_
#define ARBRE_H_

#include <vector>
#include <iostream>
#include <iomanip>
using namespace std;

#include "Symbole.h"

////////////////////////////////////////////////////////////////////////////////
class Noeud {
// classe abstraite dont dériveront toutes les classes servant à représenter l'arbre abstrait
// Remarque : la classe ne contient aucun constructeur
  public:
    virtual int  getValeur() =0 ;                             // rend la classe abstraite
    virtual void afficher(unsigned short i=0) { cout << setw(4*i) << " "; } // afficher un noeud avec une indentation (i)
    virtual ~Noeud() {}                                        // conseillé dans les classes abstraites
};

////////////////////////////////////////////////////////////////////////////////
class NoeudSeqInst : public Noeud {
// classe pour représenter un noeud "sequence d'instruction"
// qui a autant de fils que d'instructions dans la séquence
  public:
     NoeudSeqInst();                                              // construit une séquence d'instruction vide
    ~NoeudSeqInst() {}                                        // à cause du destructeur virtuel de la classe Noeud
    int getValeur();                                                 // évalue chaque instruction de la séquence
    void afficher(unsigned short i=0);                  // affiche la séquence d'instructions
    void ajouteInstruction(Noeud* instruction);  // ajoute une instruction à la séquence

  private:
    vector<Noeud *> tabInst;                              // pour stocker les instructions de la séquence
};

////////////////////////////////////////////////////////////////////////////////
class NoeudOperateurBinaire : public Noeud {
// classe pour représenter un noeud "opération arithmétique" ou une "operation booleenne"
// composé d'un opérateur (+-*/) ou (><...)
//et de 2 fils : l'opérande gauche et l'opérande droit
  public:
    NoeudOperateurBinaire(Symbole operateur, Noeud* operandeGauche, Noeud* operandeDroit);
   ~NoeudOperateurBinaire() {}
    int getValeur();  // évalue l'operande gauche, l'operande droit et applique l'opérateur
    void afficher(unsigned short i=0);

  private:
    Symbole operateur;
    Noeud*  operandeGauche;
    Noeud*  operandeDroit;
};

////////////////////////////////////////////////////////////////////////////////
class NoeudAffectation : public Noeud {
// classe pour représenter un noeud "affectation"
// composé de 2 fils : la variable et l'expression qu'on lui affecte
  public:
     NoeudAffectation(Noeud* variable, Noeud* expression); 
    ~NoeudAffectation() {} 
    int getValeur();                                            // évalue l'expression et affecte sa valeur à la variable
    void afficher(unsigned short i=0);

  private:
    Noeud* variable;
    Noeud* expression;
};

////////////////////////////////////////////////////////////////////////////////
class NoeudTerms : public Noeud {
// noeud dont derivera "tantque", "pour" et "repeter"
// et contenu du vecteur utilise par "si" et "selon"
// compose de 2 fils : la condition et les instructions qui suivent
public:
    NoeudTerms(string instruction, Noeud* expBool, Noeud* seqInst) : instruction(instruction), expBool(expBool), seqInst(seqInst) {}
    ~NoeudTerms() {}
   int  getValeur();
   void afficher(unsigned short i);
private:
    string instruction;
    Noeud* expBool;
    Noeud* seqInst; 
};

////////////////////////////////////////////////////////////////////////////////
class NoeudInstSi : public Noeud {
// classe pour représenter un noeud "si"
// compose d'1 fils : un vecteur de NoeudTerms 
public:
    NoeudInstSi() {}                    // NoeudInstSi est vide au debut
    void addCondition(string cond, Noeud* expBool, Noeud* seqInst);  // on ajoute les si (pour sinon, expBool=1)
    ~NoeudInstSi() {} 
    int  getValeur(); 
    void afficher(unsigned short i);
private:
    vector<NoeudTerms *> ens; // pour contenir si {sinonsi} (sinon)
};

////////////////////////////////////////////////////////////////////////////////
class NoeudInstTq : public NoeudTerms {
// classe pour représenter un noeud "tantque"
// compose de 2 fils (herites de NoeudTerms) : la condition et les instructions qui suivent
public:
    NoeudInstTq(Noeud* expBool, Noeud* seqInst) : NoeudTerms("Tantque", expBool, seqInst) {}
    ~NoeudInstTq() {} 
private:
};

////////////////////////////////////////////////////////////////////////////////
class NoeudInstRepeter : public NoeudTerms {
// classe pour représenter un noeud "repeter"
// compose de 2 fils (de NoeudTerms) : la condition et les instructions qui suivent
public:
    NoeudInstRepeter(Noeud* expBool, Noeud* seqInst) : NoeudTerms("Repeter", expBool, seqInst) {}
    ~NoeudInstRepeter() {} 
private:
};

////////////////////////////////////////////////////////////////////////////////
class NoeudInstPour : public Noeud {
// classe pour représenter un noeud "pour"
// compose de 4 fils : la condition et les instructions qui suivent (herites de NoeudTerms) + l'initialisation et l'incrementation
public:
    NoeudInstPour(Noeud* a1, Noeud* expBool, Noeud* a2, Noeud* seqInst) : expBool(expBool), seqInst(seqInst), a1(a1), a2(a2) {}
    ~NoeudInstPour() {} 
    void afficher(unsigned short i);
    int getValeur();
private:
    Noeud* expBool;
    Noeud* seqInst; 
    Noeud* a1;  //premiere affectation
    Noeud* a2;  //deuxieme affectation
};

////////////////////////////////////////////////////////////////////////////////
class NoeudInstSelon : public Noeud {
// classe pour représenter un noeud "selon" (version francisee du switch)
// compose de 2 fils : un vecteur de NoeudTerms (condition, instruction) + la variable concernee
public:
    NoeudInstSelon() {}    // on retient la variable concernee
    void addCase(string cond, Noeud* cas, Noeud* seqInst);  // on ajoute les case qui vont derriere (pour defaut, cas=var)
    ~NoeudInstSelon() {} 
    int  getValeur(); 
    void afficher(unsigned short i);
private:
    vector<NoeudTerms *> ens; // cas + seqInst
};

////////////////////////////////////////////////////////////////////////////////
class NoeudInstLire : public Noeud {
// classe pour représenter un noeud "lire"
// 1 seul fils : la variable concernee
public:
    NoeudInstLire(Noeud* var) : var(var) {}
    ~NoeudInstLire() {} 
    int  getValeur();
    void afficher(unsigned short i);
private:
    Noeud* var;
};

////////////////////////////////////////////////////////////////////////////////
class NoeudInstEcrire : public Noeud {
// classe pour représenter un noeud "ecrire"
// 1 seul fils : ce qu'il faut afficher
public:
    NoeudInstEcrire(Noeud* it) : it(it) {}
    ~NoeudInstEcrire() {} 
    int  getValeur();
    void afficher(unsigned short i);
private:
    Noeud* it;
};

////////////////////////////////////////////////////////////////////////////////

#endif /* ARBRE_H_ */
